﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SimpleChatApplication_Server
{
    class Server
    {
        static TcpListener Listener;
        static List<TcpClient> Clients = new List<TcpClient>();
        static List<NetworkStream> NetStream = new List<NetworkStream>();
        
        static void Main(string[] args)
        {
            Thread thrdinput = new Thread(new ThreadStart(InputManager));
            thrdinput.Start();
        }

        static void InputManager()
        {
            while (true)
            {
                string command = Console.ReadLine();
                string cmd = command.Split(' ')[0];

                switch (cmd)
                {
                    case "/exit":

                        Disconnect();
                        return;

                    case "/startserver":

                        string[] args = command.Split(' ');

                        if ((args.Length == 2) && (args[1].Length > 1))
                        {
                            try
                            {
                                int port = Convert.ToInt32(args[1]);
                                Listener = new TcpListener(IPAddress.Any, port);
                                Console.WriteLine("SERVER: Server started on port " + port.ToString());
                                Thread thrdlisten = new Thread(new ThreadStart(Listen));
                                thrdlisten.Start();
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("ERROR: " + ex.ToString());
                            }
                        }
                        else
                        {
                            Console.WriteLine("USAGE: /startserver [PORT]");
                        }

                        break;

                    default:

                        byte[] datbuf = Encoding.Default.GetBytes(command);
                        SendMessageToClients(datbuf);

                        break;
                }
            }
        }

        static void Listen()
        {
            try
            {
                Console.WriteLine("SERVER: Listening and accepting incoming connections...");
                Listener.Start();

                while (true)
                {
                    TcpClient client = Listener.AcceptTcpClient();
                    IPEndPoint endpoint = client.Client.RemoteEndPoint as IPEndPoint;
                    Console.WriteLine("SERVER: Client " + endpoint.Address.ToString() + " connected on ID " + Clients.Count.ToString()); 
                    Clients.Add(client);
                    NetStream.Add(client.GetStream());
                    Thread thrdReceive = new Thread(new ParameterizedThreadStart(ClientReceieve));
                    thrdReceive.Start(Clients.Count - 1);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: " + ex.ToString());
            }
        }

        static void ClientReceieve(object obj)
        {
            int clientid = (int)obj;
            byte[] receive = new byte[64];

            while (true)
            {
                try
                {
                    NetStream[clientid].Read(receive, 0, receive.Length);
                    string message = Encoding.Default.GetString(receive);
                    Console.WriteLine("CLIENT " + clientid.ToString() + ": " + message);
                    string content = "CLIENT " + clientid.ToString() + ": " + message;
                    byte[] datbuf = Encoding.Default.GetBytes(content);
                    SendMessageToClients(datbuf);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("ERROR: " + ex.ToString());
                    break;
                }
            }
        }

        static void SendMessageToClients(byte[] data)
        {
            foreach (NetworkStream netstream in NetStream)
            {
                netstream.Write(data, 0, data.Length);
                netstream.Flush();
            }
        }

        static void Disconnect()
        {
            Listener.Stop();

            for (int i = 0; i < Clients.Count; i++)
            {
                Clients[i].Close();
                NetStream[i].Close();
            }
        }
    }
}
